package com.centersoft.flowable.core.util;


import cn.hutool.core.lang.Assert;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.centersoft.flowable.core.annotation.WorkFlowAnnotation;
import com.centersoft.flowable.core.annotation.WorkFlowAuditType;
import com.centersoft.flowable.core.exception.FlowableRuntimeException;
import com.centersoft.flowable.core.model.ReviewRequest;
import lombok.Data;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class WorkFlowUtils {

    private static final ApplicationContext applicationContext = SpringUtil.getApplicationContext();

    private static Map<String, FlowableInvokeData> flowableData;


    /**
     * 处理业务数据
     * （统一的发起审批时会调该方法）
     *
     * @param reviewRequest 请求参数
     */
    public static void updateBusinessByType(ReviewRequest reviewRequest) {
        String menuCode = reviewRequest.getMenuCode();
        WorkFlowAuditType type = reviewRequest.getWorkFlowAuditType();


        Assert.notBlank(menuCode, "menuCode不能为空");

        //获取所有标注工作流注解的实现类
        Map<String, FlowableInvokeData> flowableBeans = getWorkFlowBeans();

        FlowableInvokeData flowableInvokeData = flowableBeans.get(menuCode);
        Assert.notNull(flowableInvokeData, menuCode + "找不到对应的实现类");

        Object bean = flowableInvokeData.getBean();
        Map<WorkFlowAuditType, Method> methods = flowableInvokeData.getMethods();
        Assert.isTrue(bean != null && methods != null && methods.get(type) != null, menuCode + "找不到" + type.getText() + "对应的审批方法");
        Method method = methods.get(type);
        try {
            //执行方法，不晓得为什么要手动设置当前用户，先屏蔽，后续遇到问题在考虑处理方法
            //            WorkFlowService workFlowService = applicationContext.getBean(WorkFlowService.class);
            //            workFlowService.updateUserInfo(reviewRequest);
            Class<?>[] parameterTypes = method.getParameterTypes();
            Class<?> parameterType = parameterTypes[0];

            if (parameterType == Map.class) {
                JSONObject json = (JSONObject) JSON.toJSON(reviewRequest);
                method.invoke(bean, json);
            } else {
                method.invoke(bean, reviewRequest);
            }
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new FlowableRuntimeException(e);
        }
    }


    private static Map<String, FlowableInvokeData> getWorkFlowBeans() {
        //运行过程中这个不会变，获取后就缓存下来
        if (!CollectionUtils.isEmpty(flowableData)) {
            return flowableData;
        }
        synchronized (WorkFlowUtils.class) {
            if (CollectionUtils.isEmpty(flowableData)) {
                flowableData = new HashMap<>();
                Map<String, Object> flowableBeans = applicationContext.getBeansWithAnnotation(WorkFlowAnnotation.class);
                flowableData = new HashMap<>(flowableBeans.size());

                for (Map.Entry<String, Object> entry : flowableBeans.entrySet()) {
                    Class<?> targetClass = AopUtils.getTargetClass(entry.getValue());
                    WorkFlowAnnotation declaredAnnotation = AnnotationUtils.findAnnotation(targetClass, WorkFlowAnnotation.class);
                    if (declaredAnnotation == null) {
                        continue;
                    }
                    String modId = declaredAnnotation.moduid();
                    String[] modIds = modId.split(",");

                    FlowableInvokeData flowableInvokeData = new FlowableInvokeData();
                    flowableInvokeData.setBean(entry.getValue());
                    flowableInvokeData.setMethods(new HashMap<>());

                    Method[] methods = targetClass.getDeclaredMethods();
                    for (Method method : methods) {
                        //获取带有流程注解的方法
                        WorkFlowAnnotation declaerMethod = AnnotationUtils.findAnnotation(method, WorkFlowAnnotation.class);
                        if (declaerMethod != null) {
                            //判断类型是否一致
                            WorkFlowAuditType workFlowAuditType = declaerMethod.type();
                            if (workFlowAuditType != null) {
                                flowableInvokeData.getMethods().put(workFlowAuditType, method);
                            }
                        }
                    }

                    for (String id : modIds) {
                        flowableData.put(id, flowableInvokeData);
                    }
                }
            }
        }

        return flowableData;
    }


    @Data
    public static class FlowableInvokeData {
        /**
         * 审核的bean
         */
        public Object bean;

        /**
         * 审核的回调方法
         */
        public Map<WorkFlowAuditType, Method> methods;
    }


}
